package pdm.traj.query.impl;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.sun.org.apache.bcel.internal.Constants;

import pdm.traj.entity.TrackPoint2;
import pdm.traj.entity.TrajQuery;
import pdm.traj.service.KeyService;
import pdm.traj.util.TrackPointUtil;
import pdm.traj.util.TrajConstants;
import redis.clients.jedis.Jedis;

/**
 * 多轨迹查询客户端
 * 负责对一个节点的查询
 * 查询slave线程
 * @author gaozhenlong
 *
 */
public class QueryMultiTraj extends Thread{
	private String TAG = "QueryMultiTraj";
	private Log log = LogFactory.getLog(QueryMultiTraj.class);
	private KeyService keyService = null;
	private List<TrackPoint2> result = null;
	private String ip = "";
	private String port = "6379";
	private List<String> keys = null;
	private List<String> uids = null;
	private Date startTime;
	private Date endTime;
	private Jedis cli = null;
	boolean checkuid;
	private SimpleDateFormat sdf = new SimpleDateFormat(TrajConstants.TIMESTAMP_FORMAT_STR);
	public void run() {
		//init
		TAG = "-tid:" + this.getId();
		//check
		if (ip.equals("")) {
			log.error(TAG + ":run() invalid ip: " + ip);
			return;
		}
		int portNum = 6379;
		try {
			portNum = Integer.parseInt(port); 
		} catch (NumberFormatException nfe) {
			log.error(TAG + ":run() invalid port: " + port);
			return;
		}
		if (keys == null) {
			log.error(TAG + ":run() keys null value");
			return;
		}
		if (keyService == null) {
			log.error(TAG + ":run() keyService null value");
			return;
		}
		if (startTime == null) {
			log.error(TAG + ":run() startTime null value");
			return;
		}
		if (endTime == null) {
			log.error(TAG + ":run() endTime null value");
			return;
		}
		checkuid = !(uids == null || uids.isEmpty());
		log.info(TAG + " receive query: " + "ip:" + ip + "port:" + port + "startTime:" + startTime.toString() + "\tendTime:" + endTime.toString());
		log.info(TAG + " execute query start");
		//query
		cli = new Jedis(ip, portNum);
		boolean success = false;
		while (!success) {
			try {
				result = new ArrayList<TrackPoint2>();
				cli.connect();
				for (String k : keys){
					List<TrackPoint2> partr = queryTPListByKeyUids(k);
					if (partr != null) {
						result.addAll(partr);
					}
				}
				cli.disconnect();
				success = true;
			} catch (Exception e) {
				log.error("run() connection error", e);
			}
		} 
		log.info(TAG + " execute query end " + result.size() + " results found");
	}


	/**
	 * query trackpoint list by redis key and uids
	 * @param key
	 * @return
	 */
//	public synchronized List<TrackPoint2> queryTPListByKeyUids(String key) {
	public  List<TrackPoint2> queryTPListByKeyUids(String key) {
		List<TrackPoint2> result = null;
		if (cli.exists(key)) {			
			result = new ArrayList<TrackPoint2>();
			String tpl;	
			tpl = cli.get(key);
			StringTokenizer st = new StringTokenizer(tpl, ";", false);
			while (st.hasMoreTokens()) {
				// get current trackpoint
				String str = st.nextToken();// uid,ts
				if (!"".equals(str)) {
					// parse trackpoint
					String[] strs = str.split(",");
					String tsStr = strs[1];// timestamp;
//					System.out.println("tsStr: " + tsStr);
					Date ts;
					
					try {
//							ts = TrajConstants.TIMESTAMP_FORMAT.parse(tsStr);
							ts = sdf.parse(tsStr);
					} catch (ParseException e) {
						log.error("bad trackpoint from redis: " + str);
//						log.error("bad trackpoint from redis: " + str, e);
						continue;
					} 
					/*catch (NumberFormatException nfe) {
						nfe.printStackTrace();
						System.out.println("tsStr: " + tsStr);
						continue;
					}
					*/
//					catch (Exception nfe) {
//						nfe.printStackTrace();
//						System.out.println("\n\n\n");
//						System.out.println("Exception :"+ nfe.getCause()+"\n"+nfe.getClass()+"\ntsStr: " + tsStr);
//						continue;
//					}
					if (ts.after(startTime) && ts.before(endTime)) {
						//TODO: to be optimized
						if (checkuid) {
							String uidStr = strs[0];
							if (uids.contains(uidStr)) {
								TrackPoint2 tp = new TrackPoint2();
								TrackPointUtil.assembleTrackPoint(key, str, tp);
								result.add(tp);
							}
						} else {
							TrackPoint2 tp = new TrackPoint2();
							TrackPointUtil.assembleTrackPoint(key, str, tp);
							result.add(tp);
						}
					}
				}
			}
		} 
		return result;
	}
//	public List<TrackPoint2> queryTPListByKeyUids(String key) {
//		List<TrackPoint2> result = null;
//		boolean checkuid = !(uids == null || uids.isEmpty());
//		if (cli.exists(key)) {			
////			String keyWithoutPrefix = keyService.removeKeyPrefix(key);
//			result = new ArrayList<TrackPoint2>();
//			String tpl;	
//			tpl = cli.get(key);
//			StringTokenizer st = new StringTokenizer(tpl, ";", false);
//			while (st.hasMoreTokens()) {
//				String str = st.nextToken();
//				if (!"".equals(str)) {
//					TrackPoint2 tp = new TrackPoint2();
////					TrackPointUtil.assembleTrackPoint(keyWithoutPrefix, str, tp);
//					TrackPointUtil.assembleTrackPoint(key, str, tp);					
//					String tsStr = tp.getTs();
//					try {
//						Date ts = TrajConstants.TIMESTAMP_FORMAT.parse(tsStr);
//						if (ts.after(startTime) && ts.before(endTime)) {
//							if (checkuid) {
//								if (uids.contains(tp.getId())) {
//									result.add(tp);
//								}
//							} else {
//								result.add(tp);
//							}
//						}
//					} catch (ParseException pe) {
//						log.error(TAG + ":queryTPListByKeyUids: bad timestamp: " + tsStr);
//					}
//				}
//			}
//		} 
//		return result;
//	}

	public List<TrackPoint2> getResult() {
		return result;
	}
	public void setResult(List<TrackPoint2> result) {
		this.result = result;
	}
	public String getIp() {
		return ip;
	}
	public void setIp(String ip) {
		this.ip = ip;
	}
	public String getPort() {
		return port;
	}
	public void setPort(String port) {
		this.port = port;
	}
	public List<String> getUids() {
		return uids;
	}
	public void setUids(List<String> uids) {
		this.uids = uids;
	}
	public List<String> getKeys() {
		return keys;
	}
	public void setKeys(List<String> keys) {
		this.keys = keys;
	}


	public void setKeyService(KeyService keyService) {
		this.keyService = keyService;
	}


	public void setStartTime(Date startTime) {
		this.startTime = startTime;
	}


	public void setEndTime(Date endTime) {
		this.endTime = endTime;
	}


}
